package cn.infinite.security.point;

import cn.infinite.security.configuration.ImageCheckCodeConfigProperties;
import cn.infinite.security.configuration.RedisKeySet;
import cn.infinite.security.configuration.SmsConfigurerProperties;
import org.apache.commons.lang.RandomStringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Optional;
import java.util.Random;

@RestController
@RequestMapping("/image-check-auth/check-code")
@ConditionalOnBean(ImageCheckCodeConfigProperties.class)
public class ImageCheckCodeEndPoint implements ImageCheckCodeGenerateAble, InitializingBean {

    private static final int XX = 15;
    @Resource
    private RedisTemplate<String, String> redisTemplate;
    private HashOperations<String, String, String> hashOperations;
    @Resource
    private ImageCheckCodeConfigProperties imageCheckCodeConfigProperties;
    @Resource
    private SmsConfigurerProperties smsConfigurerProperties;

    private Short imageWidth;
    private Short imageHeight;
    private Short codeLength;
    private Random random = new Random();

    /**
     * 当用户输入完账户，需要请求此端点
     * 判断用户是否需要输入图片验证码
     *
     * @param userId
     * @return
     */
    @Override
    @GetMapping("/need-check")
    public Boolean needImageCheck(@RequestParam("userId") String userId) {
        Integer errorCount = Integer.valueOf(Optional.ofNullable(this.hashOperations.get(RedisKeySet
                        .NEED_IMAGE_CHECK_CODE_HASH_PREFIX,
                userId)).orElseGet(() -> "0"));
        return errorCount >= this.smsConfigurerProperties.getImageCheckCodeWhenMaxFailCount();
    }

    @Override
    @GetMapping(produces = MediaType.IMAGE_JPEG_VALUE)
    public void generateCheckCodeImage(@RequestParam("userId") String userId, HttpServletResponse response) throws
            IOException {
        char[] randomCode = RandomStringUtils.randomAlphabetic(codeLength).toCharArray();
        BufferedImage buffImg = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = buffImg.createGraphics();
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, imageWidth, imageHeight);
        g.setFont(new Font("Fixedsys", Font.BOLD, (int) (imageHeight * 0.8)));
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g.setColor(Color.BLACK);
        g.setColor(Color.BLACK);
        for (int i = 0; i < 40; i++) {
            int x = random.nextInt(imageWidth);
            int y = random.nextInt(imageHeight);
            int xl = random.nextInt(12);
            int yl = random.nextInt(12);
            g.drawLine(x, y, x + xl, y + yl);
        }
        int red = 0, green = 0, blue = 0;
        // 随机产生验证码
        for (int i = 0; i < codeLength; i++) {
            // 得到随机产生的验证码数字
            String code = String.valueOf(randomCode[i]);
            // 产生随机的颜色分量来构造颜色值，这样输出的每位数字的颜色值都将不同
            red = random.nextInt(255);
            green = random.nextInt(255);
            blue = random.nextInt(255);
            // 用随机产生的颜色将验证码绘制到图像中
            g.setColor(new Color(red, green, blue));
            g.drawString(code, (i + 1) * XX, (int) (imageHeight * 0.7));
        }
        //缓存验证码
        this.hashOperations.put(RedisKeySet.IMAGE_CHECK_CODE_HASH_PREFIX, userId, new String(randomCode));
        ImageIO.write(buffImg, "JPEG", response.getOutputStream());
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        this.hashOperations = this.redisTemplate.opsForHash();
        imageWidth = imageCheckCodeConfigProperties.getWidth();
        imageHeight = imageCheckCodeConfigProperties.getHeight();
        codeLength = imageCheckCodeConfigProperties.getCodeLength();
    }
}
